import cbor from "cbor-js"
import dayjs from "dayjs"
import { HttpClient, PostmanApi } from "./generated_apis/postman_api_filbet_client_v1"
import { AxiosError } from "axios"
import type { AxiosResponse } from "axios"
import kleur from "kleur"
import { mkdirSync, writeFileSync } from "fs"

const tmp_output_dir = `./_tmp_cbor_test/${dayjs().format("YYYYMMDD_HHmmss")}`

mkdirSync(tmp_output_dir, { recursive: true })

// 共享参数
const shared_params = {
    // User info
    phone: "9999999990",
    countryCode: "63",
    password: "1234567890",
    // Temporary storage
    tmp_otpID: "",
    tmp_token: "",
    tmp_gameID: "0",
    tmp_accountID: "1853106510581583872",
}

// 定义结果类型
interface ApiResult {
    api: string
    fullApi: string
    data?: any
    error?: string
}

// 辅助函数：记录API调用结果
async function recordApiCall<T>(
    groupName: string,
    stepName: string,
    apiCall: () => Promise<AxiosResponse<T>>,
    results: any[],
    extraData?: Record<string, any>,
    onSuccess?: (response: AxiosResponse<T>) => void,
) {
    // 从函数名中提取接口名称
    const apiMethodName = apiCall.toString().match(/api\.[a-zA-Z]+\.([a-zA-Z]+)/)?.[1] || stepName

    console.log(kleur.cyan(`\n=== 执行${stepName} ===`))
    try {
        const response = await apiCall()

        // 检查响应状态，就看 status 字段是 true 还是 false
        const isSuccess = (response.data as any)?.status === true

        // 保存响应结果
        writeFileSync(
            `${tmp_output_dir}/${groupName}_${stepName.replace(/\s+/g, "_").toLowerCase()}.json`,
            JSON.stringify(
                {
                    request: {
                        url: response.config?.url,
                        method: response.config?.method,
                        headers: response.config?.headers,
                        data:
                            response.config?.data instanceof ArrayBuffer
                                ? "<<CBOR Encoded Data>>"
                                : response.config?.data
                                  ? JSON.parse(response.config.data)
                                  : null,
                    },
                    response: {
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.headers,
                        data: response.data,
                    },
                    extraData,
                    timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
                },
                null,
                2,
            ),
        )

        if (!isSuccess) {
            // 如果 status 不是 true，就是异常
            const errorMessage = (response.data as any)?.data || "接口返回 status: false"

            writeFileSync(
                `${tmp_output_dir}/${groupName}_${stepName.replace(/\s+/g, "_").toLowerCase()}_error.json`,
                JSON.stringify(
                    {
                        step: apiMethodName,
                        request: {
                            url: response.config?.url,
                            method: response.config?.method,
                            headers: response.config?.headers,
                            data:
                                response.config?.data instanceof ArrayBuffer
                                    ? "<<CBOR Encoded Data>>"
                                    : response.config?.data
                                      ? JSON.parse(response.config.data)
                                      : null,
                        },
                        response: {
                            status: response.status,
                            statusText: response.statusText,
                            headers: response.headers,
                            data: response.data,
                        },
                        error: {
                            message: errorMessage,
                        },
                        extraData,
                        timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
                    },
                    null,
                    2,
                ),
            )

            results.push({
                step: apiMethodName,
                success: false,
                error: {
                    message: errorMessage,
                },
            })

            throw new Error(errorMessage)
        }

        results.push({
            step: apiMethodName,
            success: true,
            data: response.data,
        })

        // 调用成功回调处理响应数据
        if (onSuccess) {
            onSuccess(response)
        }

        return response
    } catch (error) {
        const axiosError = error as AxiosError

        // 保存错误信息
        writeFileSync(
            `${tmp_output_dir}/${groupName}_${stepName.replace(/\s+/g, "_").toLowerCase()}_error.json`,
            JSON.stringify(
                {
                    step: apiMethodName,
                    request: {
                        url: axiosError.config?.url,
                        method: axiosError.config?.method,
                        headers: axiosError.config?.headers,
                        data:
                            axiosError.config?.data instanceof ArrayBuffer
                                ? "<<CBOR Encoded Data>>"
                                : axiosError.config?.data
                                  ? JSON.parse(axiosError.config.data)
                                  : null,
                    },
                    response: {
                        status: axiosError.response?.status,
                        statusText: axiosError.response?.statusText,
                        headers: axiosError.response?.headers,
                        data: axiosError.response?.data,
                    },
                    error: {
                        name: axiosError.name,
                        message: axiosError.message,
                        stack: axiosError.stack,
                    },
                    extraData,
                    timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
                },
                null,
                2,
            ),
        )

        results.push({
            step: apiMethodName,
            success: false,
            error: {
                message: axiosError.message,
                data: axiosError.response?.data,
            },
        })

        throw error
    }
}

// 辅助函数：创建测试组
function createTestGroup(
    groupName: string,
    tests: Array<{
        name: string
        call: () => Promise<AxiosResponse<any>>
        extraData?: Record<string, any>
        onSuccess?: (response: AxiosResponse<any>) => void
    }>,
) {
    // 保存测试数组到 test_groups 的元数据中
    const testGroup = async () => {
        const results: any[] = []

        for (const test of tests) {
            try {
                await recordApiCall(
                    groupName,
                    test.name,
                    test.call,
                    results,
                    test.extraData,
                    test.onSuccess,
                )
            } catch (error) {
                console.log(kleur.red(`测试 ${test.name} 执行异常: ${(error as Error).message}`))
                // 继续执行下一个测试
                continue
            }
        }

        // 保存测试组汇总
        writeFileSync(
            `${tmp_output_dir}/${groupName}_summary.json`,
            JSON.stringify(
                {
                    timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
                    totalSteps: results.length,
                    successSteps: results.filter((r) => r.success).length,
                    failedSteps: results.filter((r) => !r.success).length,
                    results,
                },
                null,
                2,
            ),
        )
    }

    // 添加元数据
    ;(testGroup as any).__tests = tests

    return testGroup
}

// CBOR 编解码
const cbor_encode = (data: any) => {
    return cbor.encode(data) as ArrayBuffer
}

const cbor_decode = (arrayBuffer: ArrayBuffer) => {
    return cbor.decode(arrayBuffer)
}

// 创建API客户端
const client = new HttpClient({
    baseURL: "http://client-beta.filbet2025.com",
})

// 配置请求拦截器
client.instance.interceptors.request.use((config) => {
    console.log(kleur.white(kleur.bgBlue(`/**************** ${config.url} ****************/`)))
    console.log(kleur.bgYellow("<----- 请求 ----->"))
    config.headers.d = "25"
    config.headers.lang = "en_US"
    config.responseType = "arraybuffer"
    if (shared_params.tmp_token) {
        config.headers.t = shared_params.tmp_token
    } else {
        config.headers.t = ""
    }
    console.log(kleur.red(`方法: ${config.method}`))
    console.log(kleur.red(`请求头: ${JSON.stringify(config.headers, null, 2)}`))
    if (config.data) {
        console.log(kleur.red(`请求载荷: ${JSON.stringify(config.data, null, 2)}`))
        config.data = cbor_encode(config.data)
        console.log(kleur.red(`载荷编码长度: ${config.data.byteLength}`))
    } else {
        console.log(kleur.green("请求载荷: 无数据"))
    }
    return config
})

// 配置响应拦截器
client.instance.interceptors.response.use((response) => {
    console.log(kleur.bgYellow("<----- 响应 ----->"))
    const buffer = new Uint8Array(response.data).buffer
    try {
        const data = cbor_decode(buffer)
        console.log(kleur.blue(`响应载荷: ${JSON.stringify(data, null, 2)}`))
        console.log(kleur.green(`载荷解码长度: ${buffer.byteLength}`))

        // 检查响应状态并统计
        if (data && typeof data === "object" && "status" in data) {
            if (data.status === true) {
                // 增加成功计数
                ;(client.instance as any).__successCount =
                    ((client.instance as any).__successCount || 0) + 1
                // 保存成功结果
                ;(client.instance as any).__successResults = [
                    ...((client.instance as any).__successResults || []),
                    {
                        api: response.config.url?.replace(/^.*\//, "") || "未知接口",
                        fullApi:
                            `api.${response.config.url?.split("/").slice(1).join(".")}` ||
                            "未知接口",
                        data: data,
                    },
                ]
            } else {
                // 增加异常计数
                ;(client.instance as any).__failedCount =
                    ((client.instance as any).__failedCount || 0) + 1
                // 保存异常结果
                ;(client.instance as any).__failedResults = [
                    ...((client.instance as any).__failedResults || []),
                    {
                        api: response.config.url?.replace(/^.*\//, "") || "未知接口",
                        fullApi:
                            `api.${response.config.url?.split("/").slice(1).join(".")}` ||
                            "未知接口",
                        data: data,
                    },
                ]
            }
        }

        response.data = data
    } catch (err) {
        const error = err as Error
        console.log(kleur.red(`响应解码错误: ${error.message}`))
        response.data = {
            status: false,
            data: `响应解码错误 ${JSON.stringify((error as AxiosError).response?.data, null, 2)}`,
        }
        // 增加异常计数
        ;(client.instance as any).__failedCount = ((client.instance as any).__failedCount || 0) + 1
        // 保存异常结果
        ;(client.instance as any).__failedResults = [
            ...((client.instance as any).__failedResults || []),
            {
                api: response.config.url?.replace(/^.*\//, "") || "未知接口",
                fullApi: `api.${response.config.url?.split("/").slice(1).join(".")}` || "未知接口",
                error: error.message,
            },
        ]
    }
    return response
})

const api = new PostmanApi(client)

// 定义测试组
const test_groups = {
    // 认证相关测试
    auth: createTestGroup("auth", [
        {
            name: "发送短信验证码",
            call: () =>
                api.member.sendSmsOtp({
                    phone: shared_params.phone,
                    country_code: shared_params.countryCode,
                }),
            extraData: { phone: shared_params.phone },
            onSuccess: (response) => {
                // 保存 otp_id 用于后续登录
                shared_params.tmp_otpID = response.data?.data?.id || ""
                console.log(kleur.green(`获取到 OTP ID: ${shared_params.tmp_otpID}`))
            },
        },
        {
            name: "短信验证码登录",
            call: () =>
                api.member.loginWithSmsOtpCode({
                    code: "111111",
                    otp_id: shared_params.tmp_otpID,
                }),
            onSuccess: (response) => {
                // 保存 token 用于后续请求
                shared_params.tmp_token = response.data?.data || ""
                console.log(kleur.green(`获取到 Token: ${shared_params.tmp_token}`))
            },
        },
        {
            name: "重置密码",
            call: () =>
                api.member.resetPasswordWithOtpCode({
                    otp_id: shared_params.tmp_otpID ?? "",
                    new_password: shared_params.password,
                    code: "111111",
                }),
        },
        {
            name: "密码登录",
            call: () =>
                api.member.loginWithPassword({
                    phone: shared_params.phone,
                    country_code: shared_params.countryCode,
                    password: shared_params.password,
                }),
            onSuccess: (response) => {
                // 更新 token
                shared_params.tmp_token = response.data?.data || ""
                console.log(kleur.green(`获取到新 Token: ${shared_params.tmp_token}`))
            },
        },
        {
            name: "刷新Token",
            call: () => api.member.refreshToken(),
        },
    ]),

    // 用户信息相关测试
    profile: createTestGroup("profile", [
        {
            name: "获取用户信息",
            call: () => api.member.refGetProfile(),
        },
        {
            name: "获取KYC信息",
            call: () => api.member.refGetKyc(),
        },
        {
            name: "更新用户信息",
            call: () =>
                api.member.refUpdateDetail({
                    record: {
                        email: "",
                        phone: "",
                        nick_name: "",
                        gender: "",
                    },
                    smsOtpID: "",
                    code: "",
                }),
        },
        {
            name: "短信验证码前置检查",
            call: () =>
                api.member.refPostAuthSms({
                    code: "111111",
                    country_code: "63",
                    phone: shared_params.phone,
                    otp_id: shared_params.tmp_otpID,
                }),
        },
        {
            name: "获取会员VIP信息",
            call: () => api.member.refGetMemberVip(),
        },
        {
            name: "获取首页缓存",
            call: () => api.member.refGetIndexCache(),
        },
        {
            name: "更新密码",
            call: () =>
                api.member.refUpdatePassword({
                    old_password: shared_params.password,
                    new_password: shared_params.password,
                }),
        },
        {
            name: "KYC OCR设置",
            call: () =>
                api.member.refOcrSetup({
                    biz_id: "test_biz_id",
                    id_type: "1",
                    is_frame: true,
                    complete_callback_url: "http://example.com/complete",
                    interrupt_callback_url: "http://example.com/interrupt",
                }),
        },
        {
            name: "KYC OCR结果检查",
            call: () =>
                api.member.refOrcCheckResult({
                    biz_id: "test_biz_id",
                    id_type: "1",
                    transaction_id: "test_transaction_id",
                }),
        },
        {
            name: "提交KYC信息",
            call: () =>
                api.member.refPostKyc({
                    birthday: "1990-01-01",
                    first_name: "Test",
                    gender: "1",
                    id_number: "123456789",
                    last_name: "User",
                    middle_name: "Demo",
                }),
        },
        {
            name: "更新KYC信息",
            call: () =>
                api.member.refUpdateKyc({
                    birthday: "1990-01-01",
                    first_name: "Test",
                    gender: "1",
                    id_number: "123456789",
                    last_name: "User",
                    middle_name: "Demo",
                }),
        },
    ]),

    // 钱包相关测试
    wallet: createTestGroup("wallet", [
        {
            name: "获取钱包信息",
            call: () => api.finance.refGetFinanceWallet(),
        },
        {
            name: "获取账户列表",
            call: () => api.finance.refGetFinanceAccountList(),
        },
        {
            name: "获取渠道列表",
            call: () =>
                api.finance.refGetFinanceChannelList({
                    mode: "1", // 1充值2提现
                }),
        },
        {
            name: "获取交易记录",
            call: () =>
                api.finance.refGetTransactionList({
                    time_flag: "15",
                    type: "2001",
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "获取交易奖励记录",
            call: () =>
                api.member.refGetTransactionBonus({
                    time_flag: "15",
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "添加提现账户",
            call: () =>
                api.finance.refUpdateFinanceAccount({
                    account: shared_params.phone,
                    channel_name: "maya",
                    first_name: "Test",
                    last_name: "User",
                    middle_name: "Demo",
                }),
        },
        {
            name: "删除提现账户",
            call: () =>
                api.finance.refGetFinanceAccountDelete({
                    id: shared_params.tmp_accountID,
                }),
        },
    ]),

    // 支付相关测试
    payment: createTestGroup("payment", [
        {
            name: "充值请求",
            call: () =>
                api.finance.refUpdateFinancePaymentDeposit({
                    pid: "10",
                    amount: "100",
                    device: "web",
                }),
        },
        {
            name: "提现请求",
            call: () =>
                api.finance.refGetFinancePaymentWithdraw({
                    account_id: shared_params.tmp_accountID,
                    amount: "100",
                }),
        },
        {
            name: "获取充值记录",
            call: () =>
                api.finance.refGetFinanceDepositList({
                    status: "PENDING",
                    time_flag: "0",
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "获取提现记录",
            call: () =>
                api.finance.refGetFinanceWithdrawList({
                    status: "paying",
                    time_flag: "0",
                    page: 1,
                    page_size: 10,
                }),
        },
    ]),

    // 游戏相关测试
    game: createTestGroup("game", [
        {
            name: "游戏启动",
            call: () =>
                api.game.refGetGameLaunch({
                    code: "pp_slot_angel_vs_sinner_vs15fghtmultlv",
                }),
        },
        {
            name: "获取游戏平台信息",
            call: () =>
                api.member.refGetGamePlatform({
                    game_type: "1", // 1视讯 2捕鱼 3老虎机 5棋牌 7bingo
                    state: "1", // 1开启2关闭
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "获取游戏列表",
            call: () =>
                api.member.refGetGameList({
                    game_type: "1",
                    platform_id: "pp",
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "获取游戏历史",
            call: () => api.member.refGetGameListHistory(),
        },
        {
            name: "获取游戏收藏列表",
            call: () =>
                api.member.refGetGameFavList({
                    page: 1,
                    page_size: 10,
                }),
        },
        {
            name: "添加游戏收藏",
            call: () =>
                api.member.refGetAddGameFav({
                    id: shared_params.tmp_gameID,
                }),
        },
        {
            name: "删除游戏收藏",
            call: () =>
                api.member.refGetDeleteGameFav({
                    id: shared_params.tmp_gameID,
                }),
        },
        {
            name: "获取游戏投注记录",
            call: () =>
                api.member.refGetGameBetList({
                    time_flag: "15",
                    page: 1,
                    page_size: 10,
                }),
        },
    ]),

    // 登出测试（最后执行）
    logout: createTestGroup("logout", [
        {
            name: "再次登录",
            call: () =>
                api.member.loginWithPassword({
                    phone: shared_params.phone,
                    country_code: shared_params.countryCode,
                    password: shared_params.password,
                }),
        },
        {
            name: "再次重置密码",
            call: () =>
                api.member.resetPasswordWithOtpCode({
                    otp_id: shared_params.tmp_otpID ?? "",
                    new_password: shared_params.password,
                    code: "111111",
                }),
        },
        {
            name: "登出操作",
            call: () => api.member.logout(),
        },
    ]),
}

// 执行测试
async function runTests() {
    // 重置计数器和结果存储
    ;(client.instance as any).__successCount = 0
    ;(client.instance as any).__failedCount = 0
    ;(client.instance as any).__successResults = []
    ;(client.instance as any).__failedResults = []

    const failedTests: Array<{ group: string; step: string; error: string }> = []

    // 计算总API数和测试组详情
    const groupDetails = Object.entries(test_groups).map(([name, group]) => {
        // 获取测试组中的接口数量
        const tests = (group as any).__tests || []
        const apiCount = tests.length
        return { name, apiCount }
    })

    const totalApis = groupDetails.reduce((sum, group) => sum + group.apiCount, 0)

    console.log(
        kleur.bgYellow(
            `\n开始执行测试，共 ${Object.keys(test_groups).length} 个测试组，${totalApis} 个接口\n`,
        ),
    )

    // 执行测试
    for (const [groupName, groupTest] of Object.entries(test_groups)) {
        console.log(kleur.cyan(`\n=== 执行测试组: ${groupName} ===\n`))
        try {
            await groupTest()
            console.log(kleur.green(`✓ 测试组 ${groupName} 执行完成`))
        } catch (err) {
            const error = err as Error
            console.log(kleur.red(`✗ 测试组 ${groupName} 执行失败: ${error.message}`))
            failedTests.push({
                group: groupName,
                step: error.message,
                error: error.message,
            })
            // 继续执行下一个测试组
            continue
        }
    }

    // 输出总结
    console.log(kleur.bgBlue("\n=== 接口测试执行总结 ==="))

    // 环境信息
    console.log(kleur.yellow("\n[环境信息]"))
    console.log(
        kleur.yellow("API地址：") + kleur.white(client.instance.defaults.baseURL || "未设置"),
    )
    console.log(
        kleur.yellow("测试账号：") +
            kleur.white(`${shared_params.countryCode}-${shared_params.phone}`),
    )
    console.log(kleur.yellow("输出目录：") + kleur.white(tmp_output_dir))

    // 统计信息
    console.log(kleur.yellow("\n[统计信息]"))
    console.log(kleur.yellow("总接口数：") + kleur.white(totalApis.toString()))
    const successCount = (client.instance as any).__successCount || 0
    const failedCount = (client.instance as any).__failedCount || 0
    const executedCount = successCount + failedCount
    console.log(kleur.green("成功数量：") + kleur.white(successCount.toString()))
    console.log(kleur.red("异常数量：") + kleur.white(failedCount.toString()))
    console.log(kleur.yellow("执行数量：") + kleur.white(executedCount.toString()))
    const successRate =
        executedCount > 0 ? Math.round((successCount / executedCount) * 100 * 100) / 100 : 0
    console.log(kleur.yellow("成功率：") + kleur.white(`${successRate}%`))

    // 测试组详情
    console.log(kleur.yellow("\n[测试组详情]"))
    for (const { name, apiCount } of groupDetails) {
        console.log(kleur.white(`${name}: ${apiCount} 个接口`))
    }

    // 异常接口详情
    const failedResults = ((client.instance as any).__failedResults || []) as ApiResult[]
    if (failedResults.length > 0) {
        console.log(kleur.bgRed("\n[异常接口]"))
        failedResults.forEach(({ api, fullApi, data, error }) => {
            console.log(kleur.red(`\n${fullApi}`))
            if (error) {
                console.log(kleur.white(error))
            } else if (data && typeof data === "object" && "data" in data) {
                // 只显示 data 字段的值
                console.log("data:", kleur.white(JSON.stringify(data.data, null, 2)))
            }
        })
    }

    // 保存总结到文件
    writeFileSync(
        `${tmp_output_dir}/test_summary.json`,
        JSON.stringify(
            {
                environment: {
                    api_url: client.instance.defaults.baseURL || "未设置",
                    device_id: String(client.instance.defaults.headers?.d || "未设置"),
                    language: String(client.instance.defaults.headers?.lang || "未设置"),
                    test_account: `${shared_params.countryCode}-${shared_params.phone}`,
                    output_dir: tmp_output_dir,
                },
                statistics: {
                    total_apis: totalApis,
                    total_success: (client.instance as any).__successCount || 0,
                    total_failed: (client.instance as any).__failedCount || 0,
                    success_rate: `${successRate}%`,
                },
                test_groups: groupDetails,
                failed_results: failedResults,
                timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
            },
            null,
            2,
        ),
    )
}

runTests().catch(console.error)
